package com.ybkj.daijia.api.member.v4;

import com.ybkj.daijia.Setting;
import com.ybkj.daijia.serverUtils.SettingUtils;
import com.ybkj.daijia.WxSetting;
import com.ybkj.daijia.api.driver.transport.ResultTransport;
import com.ybkj.daijia.api.util.ErrorConstantV4;
import com.ybkj.daijia.api.weixin.WeixinUtil;
import com.ybkj.daijia.api.weixin.tenpayv3.Configuration;
import com.ybkj.daijia.api.weixin.tenpayv3.GetWxOrderno;
import com.ybkj.daijia.api.weixin.tenpayv3.RequestHandler;
import com.ybkj.daijia.api.weixin.tenpayv3.Sha1Util;
import com.ybkj.daijia.api.weixin.tenpayv3.TenpayUtil;
import com.ybkj.daijia.server.event.model.ActivityCheckEvent;
import com.ybkj.daijia.server.event.model.MemberRechargeEvent;
import com.ybkj.daijia.server.mc.Passenger;
import com.ybkj.daijia.server.model.PayRecord;
import com.ybkj.daijia.server.model.PayRecord.PayRecordType;
import com.ybkj.daijia.server.reactor.ReactorVo;
import com.ybkj.daijia.server.sales.Activity.ActivityEvent;
import com.ybkj.daijia.server.service.MemberAccountService;
import com.ybkj.daijia.server.service.MemberService;
import com.ybkj.daijia.server.service.PayRecordService;
import java.io.BufferedReader;
import java.io.ByteArrayInputStream;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.math.BigDecimal;
import java.util.Iterator;
import java.util.List;
import java.util.SortedMap;
import java.util.TreeMap;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.commons.lang3.StringUtils;
import org.jdom2.Document;
import org.jdom2.Element;
import org.jdom2.input.SAXBuilder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.event.ApplicationEventMulticaster;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;

/**
 * 支付相关
 *
 * @author mqs
 */
@Controller("MemberPayV4Controller")
@RequestMapping(value = "member/api/rest/v4/pay")
public class PayController {

    private static final Logger logger = LoggerFactory.getLogger(PayController.class);

    @Autowired
    private MemberAccountService memberAccountService;

    @Autowired
    private PayRecordService payRecordService;

    @Autowired
    private MemberService memberService;

    @Autowired
    private SettingUtils settingUtils;

    @Autowired
    private ApplicationEventMulticaster applicationEventMulticaster;


    @RequestMapping(value = "wx/miniProgramRecharge")
    public synchronized @ResponseBody
    ResultTransport miniProgramRecharge(HttpServletResponse response, HttpServletRequest request,
        Long passengerId, BigDecimal money, String jsCode) {

        logger.debug("recv passengerId:{},money:{}", passengerId, money);

        if (null == passengerId || null == money) {
            return ResultTransport.getErrorBy(ErrorConstantV4.PARAM_ERROR);
        }

        Passenger passenger = memberService.findOnePassenger(passengerId);
        if (null == passenger) {
            return ResultTransport.getErrorBy(ErrorConstantV4.PASSENGER_NOT_EXISTS);
        }

        ResultTransport instance = ResultTransport.getErrorBy(ErrorConstantV4.SUCCESS);

        WxSetting wxSetting = settingUtils.getWx();
        Setting sysSetting = settingUtils.get();

        //商户相关资料
        String appid = wxSetting.getWxAppIdMP();
        String appsecret = wxSetting.getWxAppSecretMP();
        String partner = wxSetting.getWxPartnerIdMP();
        String partnerkey = wxSetting.getWxPartnerKeyMP();

        // 验证是否得到了APPID/APPSECRET/jsCode
        SortedMap<String, String> finalpackage = new TreeMap<String, String>();
        if (null == appid || appid.isEmpty()) {
            instance.setMessage(ErrorConstantV4.APPID_NOT_SET.getMessage());
            instance.setCode(ErrorConstantV4.APPID_NOT_SET.getCode());
            return instance;
        }
        if (null == appsecret || appsecret.isEmpty()) {
            instance.setMessage(ErrorConstantV4.APPSECRET_NOT_SET.getMessage());
            instance.setCode(ErrorConstantV4.APPSECRET_NOT_SET.getCode());
            return instance;
        }
        if (null == jsCode || jsCode.isEmpty()) {
            instance.setMessage(ErrorConstantV4.JSCODE_IS_EMPTY.getMessage());
            instance.setCode(ErrorConstantV4.JSCODE_IS_EMPTY.getCode());
            return instance;
        }

        // 获取该用户的openid
        String openid = WeixinUtil.getOpenid(appid, appsecret, jsCode);
        if (openid == null) {
            instance.setMessage(ErrorConstantV4.GET_USER_OPENID_ERROR.getMessage());
            instance.setCode(ErrorConstantV4.GET_USER_OPENID_ERROR.getCode());
            return instance;
        }

        //获取openId后调用统一支付接口https://api.mch.weixin.qq.com/pay/unifiedorder
        String currTime = TenpayUtil.getCurrTime();
        //8位日期
        String strTime = currTime.substring(8, currTime.length());
        //四位随机数
        String strRandom = TenpayUtil.buildRandom(6) + "";
        //10位序列号,可以自行调整。
        String strReq = strTime + strRandom;

        PayRecord payRecord = new PayRecord();
        payRecord.setAmount(money);
        payRecord.setDeviceType("miniProgram");
        payRecord.setMemberId(passenger.getId());
        payRecord.setPhone(passenger.getPhone());
        payRecord.setTradeNO(strReq);
        payRecord.setPayRecordType(PayRecordType.wx);

        payRecordService.inertRecord(payRecord);

        String createOrderURL = Configuration.createOrderURL;

        //商户号
        String mch_id = partner;
        //随机数
        String nonce_str = strReq;
        //商品描述
        String body = "会员充值";
        //商户订单号
        String out_trade_no = payRecord.getTradeNO();
        //总金额以分为单位，不带小数点
        String total_fee = String.valueOf(money.multiply(new BigDecimal(100)).intValue());
        //订单生成的机器 IP
        String spbill_create_ip = request.getRemoteAddr();

        //这里notify_url是 支付完成后微信发给该链接信息，可以判断会员是否支付成功，改变订单状态等。
        String notify_url =
            sysSetting.getWebUrl() + "/member/api/rest/v4/pay/wx/miniProgramRechargeNotify";

        String trade_type = "JSAPI";

        SortedMap<String, String> packageParams = new TreeMap<String, String>();
        packageParams.put("appid", appid);
        packageParams.put("mch_id", mch_id);
        packageParams.put("nonce_str", nonce_str);
        packageParams.put("body", body);
        packageParams.put("out_trade_no", out_trade_no);

        //这里写的金额为1 分到时修改
//			packageParams.put("total_fee", "1");  
        packageParams.put("total_fee", total_fee);
        packageParams.put("spbill_create_ip", spbill_create_ip);
        packageParams.put("notify_url", notify_url);
        packageParams.put("trade_type", trade_type);
        packageParams.put("openid", openid);

        RequestHandler reqHandler = new RequestHandler(request, response);
        reqHandler.init(appid, appsecret, partnerkey);

        String sign = reqHandler.createSign(packageParams);
        String xml = "<xml>" +
            "<appid>" + appid + "</appid>" +
            "<mch_id>" + mch_id + "</mch_id>" +
            "<nonce_str>" + nonce_str + "</nonce_str>" +
            "<sign>" + sign + "</sign>" +
            "<body><![CDATA[" + body + "]]></body>" +
            "<out_trade_no>" + out_trade_no + "</out_trade_no>" +
//					"<total_fee>"+1+"</total_fee>"+
            "<total_fee>" + total_fee + "</total_fee>" +
            "<spbill_create_ip>" + spbill_create_ip + "</spbill_create_ip>" +
            "<notify_url>" + notify_url + "</notify_url>" +
            "<trade_type>" + trade_type + "</trade_type>" +
            "<openid>" + openid + "</openid>" +
            "</xml>";

        String prepay_id = "";
        try {
            prepay_id = GetWxOrderno.getPayNo(createOrderURL, xml);
            if (prepay_id.equals("")) {
                logger.error("统一支付接口获取预支付订单出错");
            }
        } catch (Exception e1) {
            e1.printStackTrace();
        }

        String timestamp = Sha1Util.getTimeStamp();
        finalpackage.put("appId", appid);
        finalpackage.put("nonceStr", nonce_str);
        finalpackage.put("package", "prepay_id=" + prepay_id);
        finalpackage.put("signType", "MD5");
        finalpackage.put("timeStamp", timestamp);
        String finalsign = reqHandler.createSign(finalpackage);
        finalpackage.put("sign", finalsign);

        instance.setData(finalpackage);
        return instance;

    }

    //微信支付后接口
    @RequestMapping("wx/miniProgramRechargeNotify")
    public synchronized @ResponseBody
    String miniProgramRechargeNotify(HttpServletResponse response, HttpServletRequest request)
        throws Exception {

        String out_trade_no = "";

        String trade_no = "";

        try {

            BufferedReader br = new BufferedReader(new InputStreamReader(request.getInputStream()));
            String line = null;
            StringBuilder sb = new StringBuilder();
            while ((line = br.readLine()) != null) {
                sb.append(line);
            }
            String strxml = sb.toString();

            InputStream in = new ByteArrayInputStream(strxml.getBytes());
            SAXBuilder builder = new SAXBuilder();
            Document doc = builder.build(in);
            Element root = doc.getRootElement();
            List list = root.getChildren();
            Iterator it = list.iterator();
            while (it.hasNext()) {
                Element e = (Element) it.next();
                String k = e.getName();
                if (k.equals("out_trade_no")) {
                    out_trade_no = e.getText();
                } else if (k.equals("transaction_id")) {
                    trade_no = e.getText();
                }
            }

            try {
                //关闭流
                if (null != in) {
                    in.close();
                }
            } catch (Exception e) {
                e.printStackTrace();
            }

            if (StringUtils.isBlank(out_trade_no)) {
                return "FAIL";
            }

            PayRecord payRecord = payRecordService.findByTradeNO(out_trade_no);

            if (null == payRecord) {
                return "FAIL";
            }

            if (payRecord.isTreatment()) {
                return "SUCCESS";
            }

            try {
                memberService.cashRecharge(payRecord, trade_no);

                Passenger passenger = memberService.findOnePassenger(payRecord.getMemberId());

                if (null != passenger) {
                    ReactorVo rVo = new ReactorVo();
                    rVo.setPassenger(passenger);
                    rVo.setMoney(payRecord.getAmount());
                    rVo.setType("weixin");
                    MemberRechargeEvent rechargeEvent = new MemberRechargeEvent(rVo);
                    applicationEventMulticaster.multicastEvent(rechargeEvent);

                    ReactorVo rVo2 = new ReactorVo();
                    rVo2.setPassenger(passenger);
                    rVo2.setMoney(payRecord.getAmount());
                    rVo2.setActivityEvent(ActivityEvent.recharging);
                    ActivityCheckEvent activityCheckEvent = new ActivityCheckEvent(rVo2);
                    applicationEventMulticaster.multicastEvent(activityCheckEvent);
                }

                return "SUCCESS";
            } catch (Exception e) {
                e.printStackTrace();
                return "FAIL";
            }


        } catch (Exception e) {
            e.printStackTrace();
            return "FAIL";
        }

    }


    /**
     * 微信公众号客户充值
     *
     * @param response    响应对象
     * @param request     请求对象
     * @param passengerId 客户ID
     * @param money       充值金额
     * @param openId      用户openid
     * @return
     */
    @ResponseBody
    @RequestMapping(value = "wx/weixinRecharge")
    public synchronized ResultTransport weixinRecharge(
        HttpServletResponse response,
        HttpServletRequest request,
        Long passengerId,
        BigDecimal money,
        String openId) {

        logger.debug("recv passengerId:{},money:{}", passengerId, money);

        if (null == passengerId || null == money) {
            return ResultTransport.getErrorBy(ErrorConstantV4.PARAM_ERROR);
        }

        Passenger passenger = memberService.findOnePassenger(passengerId);
        if (null == passenger) {
            return ResultTransport.getErrorBy(ErrorConstantV4.PASSENGER_NOT_EXISTS);
        }

        WxSetting wxSetting = settingUtils.getWx();
        Setting sysSetting = settingUtils.get();

        // 商户相关资料
        //商户相关资料
        String appid = wxSetting.getWxAppId();
        String appsecret = wxSetting.getWxAppSecret();
        String partner = wxSetting.getWxPartnerId();
        String partnerkey = wxSetting.getWxPartnerKey();

        // 验证是否得到了APPID/APPSECRET/openId
        ResultTransport instance = ResultTransport.getErrorBy(ErrorConstantV4.SUCCESS);
        if (null == appid || appid.isEmpty()
            || null == appsecret || appsecret.isEmpty()
            || null == openId || openId.isEmpty()) {

            instance.setMessage(ErrorConstantV4.PARAM_ERROR.getMessage());
            instance.setCode(ErrorConstantV4.PARAM_ERROR.getCode());
            return instance;
        }

        // 获取openId后调用统一支付接口https://api.mch.weixin.qq.com/pay/unifiedorder
        String currTime = TenpayUtil.getCurrTime();
        // 8位日期
        String strTime = currTime.substring(8, currTime.length());
        // 四位随机数
        String strRandom = TenpayUtil.buildRandom(6) + "";
        // 10位序列号,可以自行调整。
        String strReq = strTime + strRandom;

        PayRecord payRecord = new PayRecord();
        payRecord.setAmount(money);
        payRecord.setDeviceType("微信公众号");
        payRecord.setMemberId(passenger.getId());
        payRecord.setPhone(passenger.getPhone());
        payRecord.setTradeNO(strReq);
        payRecord.setPayRecordType(PayRecordType.wx);

        payRecordService.inertRecord(payRecord);

        String createOrderURL = Configuration.createOrderURL;

        // 商户号
        String mch_id = partner;
        // 随机数
        String nonce_str = strReq;
        // 商品描述
        String body = "会员充值";
        // 商户订单号
        String out_trade_no = payRecord.getTradeNO();
        // 总金额以分为单位，不带小数点
        String total_fee = String.valueOf(money.multiply(new BigDecimal(100)).intValue());
        // 订单生成的机器 IP
        String spbill_create_ip = request.getRemoteAddr();

        // 这里notify_url是 支付完成后微信发给该链接信息，可以判断会员是否支付成功，改变订单状态等。
        String notify_url =
            sysSetting.getWebUrl() + "/member/api/rest/v4/pay/wx/weixinRechargeNotify";

        String trade_type = "JSAPI";

        SortedMap<String, String> packageParams = new TreeMap<String, String>();
        packageParams.put("appid", appid);
        packageParams.put("mch_id", mch_id);
        packageParams.put("nonce_str", nonce_str);
        packageParams.put("body", body);
        packageParams.put("out_trade_no", out_trade_no);
        packageParams.put("total_fee", total_fee);
        packageParams.put("spbill_create_ip", spbill_create_ip);
        packageParams.put("notify_url", notify_url);
        packageParams.put("trade_type", trade_type);
        packageParams.put("openid", openId);

        RequestHandler reqHandler = new RequestHandler(request, response);
        reqHandler.init(appid, appsecret, partnerkey);
        String sign = reqHandler.createSign(packageParams);

        String xml = "<xml>"
            + "<appid>" + appid + "</appid>"
            + "<mch_id>" + mch_id + "</mch_id>"
            + "<nonce_str>" + nonce_str + "</nonce_str>"
            + "<sign>" + sign + "</sign>"
            + "<body><![CDATA[" + body + "]]></body>"
            + "<out_trade_no>" + out_trade_no + "</out_trade_no>"
            + "<total_fee>" + total_fee + "</total_fee>"
            + "<spbill_create_ip>" + spbill_create_ip + "</spbill_create_ip>"
            + "<notify_url>" + notify_url + "</notify_url>"
            + "<trade_type>" + trade_type + "</trade_type>"
            + "<openid>" + openId + "</openid>"
            + "</xml>";

        String prepay_id = "";
        try {
            prepay_id = GetWxOrderno.getPayNo(createOrderURL, xml);
            if (prepay_id.equals("")) {
                logger.error("统一支付接口获取预支付订单出错");
            }
        } catch (Exception e1) {
            e1.printStackTrace();
        }

        String timestamp = Sha1Util.getTimeStamp();
        SortedMap<String, String> finalpackage = new TreeMap<String, String>();
        finalpackage.put("appId", appid);
        finalpackage.put("nonceStr", nonce_str);
        finalpackage.put("package", "prepay_id=" + prepay_id);
        finalpackage.put("signType", "MD5");
        finalpackage.put("timeStamp", timestamp);
        String finalsign = reqHandler.createSign(finalpackage);
        finalpackage.put("sign", finalsign);

        instance.setData(finalpackage);
        return instance;
    }

    /**
     * 微信公众号客户充值回调
     *
     * @param response 响应对象
     * @param request  请求对象
     * @return
     * @throws Exception
     */
    @ResponseBody
    @RequestMapping("wx/weixinRechargeNotify")
    public synchronized String weixinRechargeNotify(HttpServletResponse response,
        HttpServletRequest request) throws Exception {
        String out_trade_no = "";
        String trade_no = "";

        try {
            BufferedReader br = new BufferedReader(new InputStreamReader(request.getInputStream()));
            String line = null;
            StringBuilder sb = new StringBuilder();
            while ((line = br.readLine()) != null) {
                sb.append(line);
            }
            String strxml = sb.toString();

            InputStream in = new ByteArrayInputStream(strxml.getBytes());
            SAXBuilder builder = new SAXBuilder();
            Document doc = builder.build(in);
            Element root = doc.getRootElement();
            List list = root.getChildren();
            Iterator it = list.iterator();

            while (it.hasNext()) {
                Element e = (Element) it.next();
                String k = e.getName();
                if (k.equals("out_trade_no")) {
                    out_trade_no = e.getText();
                } else if (k.equals("transaction_id")) {
                    trade_no = e.getText();
                }
            }
            try {
                // 关闭流
                if (null != in) {
                    in.close();
                }
            } catch (Exception e) {
                e.printStackTrace();
            }

            if (StringUtils.isBlank(out_trade_no)) {
                return "FAIL";
            }

            PayRecord payRecord = payRecordService.findByTradeNO(out_trade_no);
            if (null == payRecord) {
                return "FAIL";
            }
            if (payRecord.isTreatment()) {
                return "SUCCESS";
            }

            try {
                memberService.cashRecharge(payRecord, trade_no);
                Passenger passenger = memberService.findOnePassenger(payRecord.getMemberId());
                if (null != passenger) {
                    ReactorVo rVo = new ReactorVo();
                    rVo.setPassenger(passenger);
                    rVo.setMoney(payRecord.getAmount());
                    rVo.setType("weixin");
                    MemberRechargeEvent rechargeEvent = new MemberRechargeEvent(rVo);
                    applicationEventMulticaster.multicastEvent(rechargeEvent);

                    ReactorVo rVo2 = new ReactorVo();
                    rVo2.setPassenger(passenger);
                    rVo2.setMoney(payRecord.getAmount());
                    rVo2.setActivityEvent(ActivityEvent.recharging);
                    ActivityCheckEvent activityCheckEvent = new ActivityCheckEvent(rVo2);
                    applicationEventMulticaster.multicastEvent(activityCheckEvent);
                }

                return "SUCCESS";
            } catch (Exception e) {
                e.printStackTrace();
                return "FAIL";
            }

        } catch (Exception e) {
            e.printStackTrace();
            return "FAIL";
        }
    }
}
